热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

分布区|发生_Redis与本地缓存组合食用,味道更佳!

篇首语:本文由编程笔记#小编为大家整理,主要介绍了Redis与本地缓存组合食用,味道更佳!相关的知识,希望对你有一定的参考价值。点击关注公众号&#

篇首语:本文由编程笔记#小编为大家整理,主要介绍了Redis与本地缓存组合食用,味道更佳!相关的知识,希望对你有一定的参考价值。


点击关注公众号,实用技术文章及时了解


前言


我们开发中经常用到Redis作为缓存,将高频数据放在Redis中能够提高业务性能,降低mysql等关系型数据库压力,甚至一些系统使用Redis进行数据持久化,Redis松散的文档结构非常适合业务系统开发,在精确查询,数据统计业务有着很大的优势。


但是高频数据流处理系统中,Redis的压力也会很大,同时I/0开销才是耗时的主要原因,这时候为了降低Redis读写压力我们可以用到本地缓存,Guava为我们提供了优秀的本地缓存API,包含了过期策略等等,编码难度低,个人非常推荐。


设计示例


Redis懒加载缓存


数据在新增到MySQL不进行缓存,在精确查找进行缓存,做到查询即缓存,不查询不缓存


流程图



代码示例


// 伪代码示例 Xx代表你的的业务对象 如User Goods等等
public class XxLazyCache 
    @Autowired
    private RedisTemplate redisTemplate;
    
    @Autowired
    private XxService xxService;// 你的业务service
    
    /**
     * 查询 通过查询缓存是否存在驱动缓存加载 建议在前置业务保证id对应数据是绝对存在于数据库中的
     */
    public Xx getXx(int id) 
        // 1.查询缓存里面有没有数据
        Xx xxCache = getXxFromCache(id);
        if(xxCache != null) 
            return xxCache;// 卫语句使代码更有利于阅读
        
        // 2.查询数据库获取数据 我们假定到业务这一步,传过来的id都在数据库中有对应数据
        Xx xx = xxService.getXxById(id);
        // 3.设置缓存、这一步相当于Redis缓存懒加载,下次再查询此id,则会走缓存
        setXxFromCache(xx);
        return xx;
        
    
    
    /**
     * 对xx数据进行修改或者删除操作 操作数据库成功后 删除缓存
     * 删除请求 - 删除数据库数据 删除缓存
     * 修改请求 - 更新数据库数据 删除缓存 下次在查询时候就会从数据库拉取新的数据到缓存中
     */
    public void deleteXxFromCache(long id) 
        String key = "Xx:" + xx.getId();
        redisTemplate.delete(key);
    
    
    private void setXxFromCache(Xx xx) 
        String key = "Xx:" + xx.getId();
        redisTemplate.opsForValue().set(key, xx);
    
    
    private Xx getXxFromCache(int id) 
        // 通过缓存前缀拼装唯一主键作为缓存Key 如Xxx信息 就是Xxx:id
        String key = "Xx:" + id;
        return redisTemplate.opsForValue().get(key);
    
    
// 业务类
public class XxServie 
    @Autowired
    private XxLazyCache xxLazyCache;
    // 查询数据库
    public Xx getXxById(long id) 
        // 省略实现
        return xx;
    
    
    public void updateXx(Xx xx) 
        // 更新MySQL数据 省略
        // 删除缓存
        xxLazyCache.deleteXxFromCache(xx.getId());
    
    
    public void deleteXx(long id) 
        // 删除MySQL数据 省略
        // 删除缓存
        xxLazyCache.deleteXxFromCache(xx.getId());
    
// 实体类
@Data
public class Xx 
    // 业务主键
    private Long id;
    // ...省略

优点


  • 保证最小的缓存量满足精确查询业务,避免冷数据占用宝贵的内存空间

  • 对增删改查业务入侵小、删除即同步

  • 可插拔,对于老系统升级,历史数据无需在启动时初始化缓存


缺点


  • 数据量需可控,在无限增长业务场景不适用

  • 在微服务场景不利于全局缓存应用


总结


  • 空间最小化

  • 满足精确查询场景

  • 总数据量可控推荐使用

  • 微服务场景不适用


Redis结合本地缓存


微服务场景下,多个微服务使用一个大缓存,流数据业务下,高频读取缓存对Redis压力很大,我们使用本地缓存结合Redis缓存使用,降低Redis压力,同时本地缓存没有连接开销,性能更优


流程图



业务场景


在流处数处理过程中,微服务对多个设备上传的数据进行处理,每个设备有一个code,流数据的频率高,在消息队列发送过程中使用分区发送,我们需要为设备code生成对应的自增号,用自增号对kafka中topic分区数进行取模,这样如果有10000台设备,自增号就是0~9999,在取模后就进行分区发送就可以做到每个分区均匀分布。


这个自增号我们使用redis的自增数生成,生成后放到redis的hash结构进行缓存,每次来一个设备,我们就去这个hash缓存中取,没有取到就使用自增数生成一个,然后放到redis的hash缓存中,这时候每个设备的自增数一经生成是不会再发生改变的,我们就想到使用本地缓存进行优化,避免高频的调用redis去获取,降低redis压力。


下面链接是关于kafka分区消费的文章,大家可以去看看



https://juejin.cn/post/6995746569580445709



代码示例


/**
 * 此缓存演示如何结合redis自增数 hash 本地缓存使用进行设备自增数的生成、缓存、本地缓存
 * 本地缓存使用Guava Cache
 */
public class DeviceIncCache 
    /**
     * 本地缓存
     */
    private Cache localCache = CacheBuilder.newBuilder()
        .concurrencyLevel(16) // 并发级别
        .initialCapacity(1000) // 初始容量
        .maximumSize(10000) // 缓存最大长度
        .expireAfterAccess(1, TimeUnit.HOURS) // 缓存1小时没被使用就过期
        .build();
    @Autowired
    private RedisTemplate redisTemplate;
    
    /**
     * redis自增数缓存的key
     */
    private static final String DEVICE_INC_COUNT = "device_inc_count";
    
    /**
     * redis设备编码对应自增数的hash缓存key
     */
    private static final String DEVICE_INC_VALUE = "device_inc_value";
    
    /**
     * 获取设备自增数
     */
    public int getInc(String deviceCode)
        // 1.从本地缓存获取
        Integer inc = localCache.get(deviceCode);
        if(inc != null) 
            return inc;
        
        // 2.本地缓存未命中,从redis的hash缓存获取
        inc = (Integer)redisTemplate.opsForHash().get(DEVICE_INC_VALUE, deviceCode);
        // 3. redis的hash缓存中没有,说明是新设备,先为设备生成一个自增号
        if(inc == null) 
            inc = redisTemplate.opsForValue().increment(DEVICE_INC_COUNT).intValue;
            // 添加到redis hash缓存
            redisTemplate.opsForHash().put(DEVICE_INC_VALUE, deviceCode, inc);
        
        // 4.添加到本地缓存
        localCache.put(deviceCode, inc);
        // 4.返回自增数
        return inc;
    
    

优点


  • redis保证数据可持久,本地缓存保证超高的读取性能,微服务共用redis大缓存的场景能有效降低redis压力

  • guava作为本地缓存,提供了丰富的api,过期策略,最大容量,保证服务内存可控,冷数据不会长期占据内存空间

  • 服务重启导致的本地缓存清空不会影响业务进行

  • 微服务及分布式场景使用,分布式情况下每个服务实例只会缓存自己接入的那一部分设备的自增号,本地内存空间最优

  • 在示例业务中,自增数满足了分布区发送的均匀分布需求,也可以满足统计设备接入数目的业务场景,一举两得


缺点


  • 增加编码复杂度,不直接

  • 只适用于缓存内容只增不改的场景


总结


  • 本地缓存空间可控,过期策略优

  • 适用于微服务及分布式场景

  • 缓存内容不能发生改变

  • 性能优


后记


redis提供了丰富的数据类型及api,非常适合业务系统开发,统计计数(increment,decrement),标记位(bitmap),松散数据(hash),先进先出、队列式读取(list);


guava缓存作为本地缓存,能够高效的读取的同时,提供了大量api方便我们控制本地缓存的数据量及冷数据淘汰;我们充分的学习这些特性能够帮助我们在业务开发中更加轻松灵活,在空间与时间上找到一个平衡点。


来源:juejin.cn/post/7000263632151904293


推荐


Java面试题宝典


技术内卷群,一起来学习!!



PS:因为公众号平台更改了推送规则,如果不想错过内容,记得读完点一下“在看”,加个“星标”,这样每次新文章推送才会第一时间出现在你的订阅列表里。点“在看”支持我们吧!


推荐阅读
  • 2021最新总结网易/腾讯/CVTE/字节面经分享(附答案解析)
    本文分享作者在2021年面试网易、腾讯、CVTE和字节等大型互联网企业的经历和问题,包括稳定性设计、数据库优化、分布式锁的设计等内容。同时提供了大厂最新面试真题笔记,并附带答案解析。 ... [详细]
  • 本文介绍了Redis的基础数据结构string的应用场景,并以面试的形式进行问答讲解,帮助读者更好地理解和应用Redis。同时,描述了一位面试者的心理状态和面试官的行为。 ... [详细]
  • python中安装并使用redis相关的知识
    本文介绍了在python中安装并使用redis的相关知识,包括redis的数据缓存系统和支持的数据类型,以及在pycharm中安装redis模块和常用的字符串操作。 ... [详细]
  • 本文介绍了Python高级网络编程及TCP/IP协议簇的OSI七层模型。首先简单介绍了七层模型的各层及其封装解封装过程。然后讨论了程序开发中涉及到的网络通信内容,主要包括TCP协议、UDP协议和IPV4协议。最后还介绍了socket编程、聊天socket实现、远程执行命令、上传文件、socketserver及其源码分析等相关内容。 ... [详细]
  • 开发笔记:加密&json&StringIO模块&BytesIO模块
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了加密&json&StringIO模块&BytesIO模块相关的知识,希望对你有一定的参考价值。一、加密加密 ... [详细]
  • Spring特性实现接口多类的动态调用详解
    本文详细介绍了如何使用Spring特性实现接口多类的动态调用。通过对Spring IoC容器的基础类BeanFactory和ApplicationContext的介绍,以及getBeansOfType方法的应用,解决了在实际工作中遇到的接口及多个实现类的问题。同时,文章还提到了SPI使用的不便之处,并介绍了借助ApplicationContext实现需求的方法。阅读本文,你将了解到Spring特性的实现原理和实际应用方式。 ... [详细]
  • yum安装_Redis —yum安装全过程
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了Redis—yum安装全过程相关的知识,希望对你有一定的参考价值。访问https://redi ... [详细]
  • 开发笔记:Java是如何读取和写入浏览器Cookies的
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了Java是如何读取和写入浏览器Cookies的相关的知识,希望对你有一定的参考价值。首先我 ... [详细]
  • Java程序设计第4周学习总结及注释应用的开发笔记
    本文由编程笔记#小编为大家整理,主要介绍了201521123087《Java程序设计》第4周学习总结相关的知识,包括注释的应用和使用类的注释与方法的注释进行注释的方法,并在Eclipse中查看。摘要内容大约为150字,提供了一定的参考价值。 ... [详细]
  • 本文讨论了微软的STL容器类是否线程安全。根据MSDN的回答,STL容器类包括vector、deque、list、queue、stack、priority_queue、valarray、map、hash_map、multimap、hash_multimap、set、hash_set、multiset、hash_multiset、basic_string和bitset。对于单个对象来说,多个线程同时读取是安全的。但如果一个线程正在写入一个对象,那么所有的读写操作都需要进行同步。 ... [详细]
  • 篇首语:本文由编程笔记#小编为大家整理,主要介绍了软件测试知识点之数据库压力测试方法小结相关的知识,希望对你有一定的参考价值。 ... [详细]
  • Centos下安装memcached+memcached教程
    本文介绍了在Centos下安装memcached和使用memcached的教程,详细解释了memcached的工作原理,包括缓存数据和对象、减少数据库读取次数、提高网站速度等。同时,还对memcached的快速和高效率进行了解释,与传统的文件型数据库相比,memcached作为一个内存型数据库,具有更高的读取速度。 ... [详细]
  • 本文介绍了在Android开发中使用软引用和弱引用的应用。如果一个对象只具有软引用,那么只有在内存不够的情况下才会被回收,可以用来实现内存敏感的高速缓存;而如果一个对象只具有弱引用,不管内存是否足够,都会被垃圾回收器回收。软引用和弱引用还可以与引用队列联合使用,当被引用的对象被回收时,会将引用加入到关联的引用队列中。软引用和弱引用的根本区别在于生命周期的长短,弱引用的对象可能随时被回收,而软引用的对象只有在内存不够时才会被回收。 ... [详细]
  • MySQL数据库锁机制及其应用(数据库锁的概念)
    本文介绍了MySQL数据库锁机制及其应用。数据库锁是计算机协调多个进程或线程并发访问某一资源的机制,在数据库中,数据是一种供许多用户共享的资源,如何保证数据并发访问的一致性和有效性是数据库必须解决的问题。MySQL的锁机制相对简单,不同的存储引擎支持不同的锁机制,主要包括表级锁、行级锁和页面锁。本文详细介绍了MySQL表级锁的锁模式和特点,以及行级锁和页面锁的特点和应用场景。同时还讨论了锁冲突对数据库并发访问性能的影响。 ... [详细]
  • PHP组合工具以及开发所需的工具
    本文介绍了PHP开发中常用的组合工具和开发所需的工具。对于数据分析软件,包括Excel、hihidata、SPSS、SAS、MARLAB、Eview以及各种BI与报表工具等。同时还介绍了PHP开发所需的PHP MySQL Apache集成环境,包括推荐的AppServ等版本。 ... [详细]
author-avatar
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有